package com.pc.admin.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 *  统一日志管理
 *
 * @author 吕飞扬
 * @date 2023/6/22 21:43
 */
@Component
@Slf4j
@Aspect
public class LogAspect implements ApplicationContextAware {
    /**
     * 当前环境
     */
    private  Environment env;

    public LogAspect(Environment environment){
        this.env=environment;
    }
    private  ApplicationContext applicationContext;
    /**
     * spring框架切入点
     */
    @Pointcut("@within(org.springframework.stereotype.Repository)"+
            "|| @within(org.springframework.stereotype.Service)"+
            "|| @within(org.springframework.web.bind.annotation.RestController)")
    public void springBeanPointcut(){

    }

    /**
     * 项目切入点
     * @param
     * @return
     */
    @Pointcut("within(com.pc.admin.config..*)"+
            "||within(com.pc.admin.service..*)"+
            "||within(com.pc.admin.controller..*)")
    public void applicationPackagePointcut(){

    }


    @Around("applicationPackagePointcut() && springBeanPointcut()")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable{
        Object proceed = null;
        try {
            if(log.isInfoEnabled()) {
                log.info("进入:{}.{}(),入参[k]:{},入参[v]:{},", joinPoint.getSignature().getDeclaringType(), joinPoint.getSignature().getName(),((CodeSignature)joinPoint.getSignature()).getParameterNames(), joinPoint.getArgs());
            }
            proceed = joinPoint.proceed();

            if (log.isInfoEnabled()) {
                log.info("退出:{}.{}(),结果:{}", joinPoint.getSignature().getDeclaringType(), joinPoint.getSignature().getName(), proceed);
            }

        } catch (Throwable e) {
            log.error("IllegalAccessError:{}.{}(),入参[v]:{},e:{}", joinPoint.getSignature().getDeclaringType(), joinPoint.getSignature().getName(), joinPoint.getArgs(), e);
            throw e;
        }
        return proceed;
    }
    @AfterThrowing(pointcut = "springBeanPointcut() && applicationPackagePointcut()",throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e){
//        Environment environment = applicationContext.getEnvironment();
        //判断运行环境
        if( env.acceptsProfiles(Profiles.of("dev", "test"))){
            log.error("错误方法：{}.{}()，cause:{},exception:{}",joinPoint.getSignature().getDeclaringType(),joinPoint.getSignature().getName(),
                    e.getCause() != null ? e.getCause() : "Null",
                    e.getMessage()!= null ? e.getMessage() : "Null");
        }else {
            log.error("错误方法：{}.{}()，cause:{},time:{}",joinPoint.getSignature().getDeclaringType(),
                    joinPoint.getSignature().getName(),  e.getCause() != null ? e.getCause() : "Null",
                    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }

    }

    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
